package cc.rengu.igas.route.core.realize.impl;

import cc.rengu.igas.route.common.constant.SmartRouteParamConstant;
import cc.rengu.igas.route.common.dao.DyncDataStaticMapper;
import cc.rengu.igas.route.common.dao.RuleCfgMapper;
import cc.rengu.igas.route.common.dao.impl.DyncDataStaticMapperImpl;
import cc.rengu.igas.route.common.dao.impl.RuleCfgMapperImpl;
import cc.rengu.igas.route.common.entity.DyncDataStatic;
import cc.rengu.igas.route.common.entity.RuleCfg;
import cc.rengu.igas.route.common.enums.RouteRuleTypeEnum;
import cc.rengu.igas.route.common.enums.RouteTxnNumEnum;
import cc.rengu.igas.route.common.util.IPv4Util;
import cc.rengu.igas.route.core.realize.RouterDataInit;
import cc.rengu.jradp.mods.dbs.Database;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.ChannelCallCfgMapper;
import cc.rengu.oltp.service.common.dao.impl.ChannelCallCfgMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.utility.util.BeanUtil;
import cc.rengu.oltp.utility.util.DateUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.utility.cache.UnifiedCache;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 加载智能路由动态数据统计表
 * 1. 如有无效的路由静态配置数据则统计数据删除
 *
 * @author xionglz
 * @version 1.0
 * @date 2020-03-24
 */
public class RouterDataInitSmartDyncData implements RouterDataInit {
    private RgLogger rglog = RgLog.getLogger(this.getClass().getName());
    private static ReentrantLock lock = new ReentrantLock();
    private static boolean update = false;

    public static boolean isUpdate() {
        return update;
    }

    void waitload() {
        boolean islocked = false;
        try {
            islocked = lock.tryLock(3, TimeUnit.SECONDS);
        } catch (Exception e) {
            rglog.error(cc.rengu.utility.base.StringUtil.ExceptionToString(e));
        } finally {
            if (islocked) {
                lock.unlock();
            }
        }
    }

    @Override
    public int loadRouterData() throws Exception {
        lock.lock();
        try {
            update = true;
            //开启游标查询所有智能路由规则配置表
            RuleCfgMapper ruleCfgMapper = new RuleCfgMapperImpl();
            List<RuleCfg> listRuleCfg = ruleCfgMapper.getAllRuleCfg();
            if (null == listRuleCfg || listRuleCfg.isEmpty()) {
                rglog.info("路由配置表无数据，无需加载！");
                return 0;
            }
            rglog.info("智能路由动态统计数据落地及加载本地缓存开始");
            for (RuleCfg ruleCfg : listRuleCfg) {
                if (!RouteRuleTypeEnum.SMART.getCode().equalsIgnoreCase(ruleCfg.getRuleType())) {
                    continue;
                }
                //落地动态数据+加载内存
                saveDyncDataSmart(ruleCfg);
            }
            rglog.info("智能路由动态统计数据落地及加载本地缓存成功");
            return 0;
        } finally {
            lock.unlock();
            update = false;
        }
    }

    public int loadRouterDataByInst(String instId) throws Exception {
        if (StringUtil.isEmptyOrNull(instId) || AppParamConstant.DEFAULT_INSTID.equals(instId)) {
            rglog.error("必须上送机构,且机构不能为默认机构");
            return -1;
        }
        //开启游标查询所有智能路由规则配置表
        RuleCfgMapper ruleCfgMapper = new RuleCfgMapperImpl();
        List<RuleCfg> listRuleCfg = ruleCfgMapper.getAllRuleCfg();
        if (null == listRuleCfg || listRuleCfg.isEmpty()) {
            rglog.info("路由配置表无数据，无需加载！");
            return 0;
        }
        rglog.info("智能路由动态统计数据落地及加载本地缓存开始");
        for (RuleCfg ruleCfg : listRuleCfg) {
            if (!ruleCfg.getInstId().equals(instId)) {
                continue;
            }
            if (!RouteRuleTypeEnum.SMART.getCode().equalsIgnoreCase(ruleCfg.getRuleType())) {
                continue;
            }
            //落地动态数据+加载内存
            saveDyncDataSmart(ruleCfg);
        }
        rglog.info("智能路由动态统计数据落地及加载本地缓存成功");
        return 0;
    }

    private void saveDyncDataSmart(RuleCfg ruleCfg) throws Exception {
        //查询数据库
        DyncDataStaticMapper dyncDataStaticMapper = new DyncDataStaticMapperImpl();
        List<DyncDataStatic> dyncDataStatics = dyncDataStaticMapper.getDyncDataStaticByMachine(AppParamConstant.DEFAULT_INSTID, IPv4Util.ipv4Address);
        if (dyncDataStatics == null) {
            //智能路由 代收、代付、鉴权业务支持的所有通道都需要入库
            //查询交易码映射表获取当前业务即TXN_GROUP支持的交易
            //2200 代收对应P01CP002交易 2300代付对应P01CP001交易 2400鉴权对应T00CP002
            RouteTxnNumEnum txnNumEnum = RouteTxnNumEnum.getInstanceFromTxnGroup(ruleCfg.getTxnGroup());
            if (null == txnNumEnum) {
                rglog.warn("<{}>不支持的业务类型", ruleCfg.getTxnGroup());
                return;
            }
            ChannelCallCfgMapper channelCallCfgMapper = new ChannelCallCfgMapperImpl();
            List<ChannelCallCfg> ChannelCallCfgs = channelCallCfgMapper.selectChannelCallCfgByTxnNum(ruleCfg.getInstId(), SmartRouteParamConstant.IGRT,
                    SmartRouteParamConstant.ALL, txnNumEnum.getTxnNum(), SmartRouteParamConstant.STRING_TWO_ZERO);
            if (null == ChannelCallCfgs || ChannelCallCfgs.isEmpty()) {
                rglog.warn("{}没有支持的通道", txnNumEnum.getDesc());
                return;
            }
            dyncDataStatics = new ArrayList<>();
            for (ChannelCallCfg channelCallCfg : ChannelCallCfgs) {
                rglog.info("通道<{}>动态统计数据落表开始", channelCallCfg.getCallChannelId());
                DyncDataStatic dyncDataStatic = new DyncDataStatic();
                dyncDataStatic.setInstId(AppParamConstant.DEFAULT_INSTID);
                dyncDataStatic.setChannelId(channelCallCfg.getCallChannelId());
                dyncDataStatic.setAvgStress(0);
                dyncDataStatic.setAvgTimeCost(0);
                dyncDataStatic.setMachineId(IPv4Util.ipv4Address);
                dyncDataStatic.setNodeAvgStress(0);
                dyncDataStatic.setNodeAvgTimeCost(0);
                dyncDataStatic.setNodeSuccRate(100);
                dyncDataStatic.setSuccRate(100);
                dyncDataStatic.setUpdateTime(DateUtil.getCurrentDateTime(SmartRouteParamConstant.FORMAT_DATE_TIME23));
                int iRetCode = dyncDataStaticMapper.insertDyncDataStatic(dyncDataStatic);
                if (Database.DBS_PKEY_DUPLICATE == iRetCode) {
                    DyncDataStatic dyncDataStaticNew = dyncDataStaticMapper.getDyncDataStatic(AppParamConstant.DEFAULT_INSTID, ruleCfg.getTransChannelId(), IPv4Util.ipv4Address);
                    rglog.info("通道<{}>已经落表，当前数据如下：{}", channelCallCfg.getCallChannelId(), JSON.toJSONString(dyncDataStaticNew));
                    BeanUtil.beanCopy(dyncDataStaticNew, dyncDataStatic);
                } else if (Database.DBS_SUCCESS == iRetCode) {
                    rglog.info("通道<{}>动态统计数据首次落表成功", channelCallCfg.getCallChannelId());
                } else {
                    rglog.info("通道<{}>动态统计数据首次落表失败", channelCallCfg.getCallChannelId());
                    throw new Exception("通道" + channelCallCfg.getCallChannelId() + "动态统计数据落表失败");
                }
                dyncDataStatics.add(dyncDataStatic);
            }
        }
        if (dyncDataStatics.size() != 0) {
            rglog.info("智能路由动态统计数据存入系统缓存开始");
            //将智能路由动态数据统计表存入系统缓存
            for (DyncDataStatic dyncDataStatic : dyncDataStatics) {
                //拼接智能路由动态数据统计key值
                String key = AppParamConstant.DEFAULT_INSTID + ":" + dyncDataStatic.getChannelId() + ":" + dyncDataStatic.getMachineId();
                //重启后将通道压力置0
                dyncDataStatic.setNodeAvgStress(0);
                //TODO redis中的通道整体压力减去原数据库记录的值
                //TODO 通道整体的成功率从redis取，若无数据则继续使用原有值
                //TODO 通道整体的响应时间从redis取，若无数据则继续使用原有值
                UnifiedCache.set(SmartRouteParamConstant.ROUTE_DATA_SMART, key, dyncDataStatic);
                rglog.info("智能路由动态统计数据存入系统缓存成功，<key:{}>", key);
            }
            rglog.info("智能路由动态统计数据存入系统缓存结束");
        }
    }

}
